//
//  DKRecordVideoView.m
//  DKShortVideo
//
//  Created by Keer_LGQ on 2018/4/3.
//  Copyright © 2018年 DK. All rights reserved.
//

#import "DKRecordVideoView.h"

#import "DKCapturePipeline.h"
#import "OpenGLPixelBufferView.h"

@interface DKRecordVideoView ()<DKCapturePipelineDelegate>
{
    BOOL _addedObservers;
    BOOL _recording;
    UIBackgroundTaskIdentifier _backgroundRecordingID;
    BOOL _allowedToUseGPU;
    
    NSTimer *_labelTimer;
  
}
@property (nonatomic ,strong) OpenGLPixelBufferView *previewView;
@property (nonatomic ,strong) DKCapturePipeline *capturePipeline;

@property(nonatomic, strong) UILabel *framerateLabel;
@property(nonatomic, strong) UILabel *dimensionsLabel;
@end
@implementation DKRecordVideoView

#pragma mark - instancetype delloc
- (instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {
        [self configNotification];
        
        // the willEnterForeground and didEnterBackground notifications are subsequently used to update _allowedToUseGPU
        _allowedToUseGPU = ( [UIApplication sharedApplication].applicationState != UIApplicationStateBackground );
        self.capturePipeline.renderingEnabled = _allowedToUseGPU;
    }
    return self;
}

- (void)dealloc
{
    if ( _addedObservers )
    {
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:[UIApplication sharedApplication]];
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillEnterForegroundNotification object:[UIApplication sharedApplication]];
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:[UIDevice currentDevice]];
        [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
    }
    NSLog(@"*******************************%@: dealloc", [self class]);
}


#pragma mark - View lifecycle

- (void)applicationDidEnterBackground
{
    // Avoid using the GPU in the background
    _allowedToUseGPU = NO;
    self.capturePipeline.renderingEnabled = NO;
    
    [self.capturePipeline stopRecording]; // a no-op if we aren't recording
    
    // We reset the OpenGLPixelBufferView to ensure all resources have been cleared when going to the background.
    [self.previewView reset];
}

- (void)applicationWillEnterForeground
{
    _allowedToUseGPU = YES;
    self.capturePipeline.renderingEnabled = YES;
}

- (void)willMoveToSuperview:(UIView *)newSuperview {
    if (!newSuperview) {
        [_labelTimer invalidate];
        _labelTimer = nil;
        
        [self.capturePipeline stopRunning];
        
    }else {
        
        [self.capturePipeline startRunning];
        
        _labelTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(updateLabels) userInfo:nil repeats:YES];
    }

    [super willMoveToSuperview:newSuperview];
}

- (void)didMoveToSuperview {
    [super didMoveToSuperview];
    if (!self.superview) {
        [_labelTimer invalidate];
        _labelTimer = nil;
    }else {
        if (self.recordStopedBlock) {
            self.recordStopedBlock([DKCapturePipeline thumbnailImageForVideo:[_capturePipeline getLastedTempVideoUrl] atTime:[NSDate date].timeIntervalSinceNow], [_capturePipeline getLastedTempVideoUrl]);
        }
    }
}

- (void)layoutSubviews
{
    [self addSubview:self.previewView];
    [self addSubview:self.framerateLabel];
    [self addSubview:self.dimensionsLabel];
}

#pragma mark config
- (void)configNotification
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(applicationDidEnterBackground)
                                                 name:UIApplicationDidEnterBackgroundNotification
                                               object:[UIApplication sharedApplication]];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(applicationWillEnterForeground)
                                                 name:UIApplicationWillEnterForegroundNotification
                                               object:[UIApplication sharedApplication]];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(deviceOrientationDidChange)
                                                 name:UIDeviceOrientationDidChangeNotification
                                               object:[UIDevice currentDevice]];
    _addedObservers = YES;
    
    // Keep track of changes to the device orientation so we can update the capture pipeline
    [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
    
    _addedObservers = YES;

}

#pragma mark public

- (void)toggleRecording
{
    if ( _recording )
    {
        [_capturePipeline stopRecording];
    }
    else
    {
        // Disable the idle timer while recording
        [UIApplication sharedApplication].idleTimerDisabled = YES;
        
        // Make sure we have time to finish saving the movie if the app is backgrounded during recording
        if ( [[UIDevice currentDevice] isMultitaskingSupported] ) {
            _backgroundRecordingID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{}];
        }
        
        [_capturePipeline startRecording];
        
        _recording = YES;
    }

}

- (void)recordingStopped
{
    _recording = NO;
    [_capturePipeline stopRecording];
    [UIApplication sharedApplication].idleTimerDisabled = NO;
    
    [[UIApplication sharedApplication] endBackgroundTask:_backgroundRecordingID];
    _backgroundRecordingID = UIBackgroundTaskInvalid;
}

- (BOOL)isRecording
{
    return _recording;
}

#pragma mark selector
- (void)deviceOrientationDidChange
{
    UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
    
    // Update the recording orientation if the device changes to portrait or landscape orientation (but not face up/down)
    if ( UIDeviceOrientationIsPortrait( deviceOrientation ) || UIDeviceOrientationIsLandscape( deviceOrientation ) )
    {
        self.capturePipeline.recordingOrientation = (AVCaptureVideoOrientation)deviceOrientation;
    }
}

- (void)updateLabels
{
    NSString *frameRateString = [NSString stringWithFormat:@"%d FPS", (int)roundf( _capturePipeline.videoFrameRate )];
    self.framerateLabel.text = frameRateString;
    
    NSString *dimensionsString = [NSString stringWithFormat:@"%d x %d", _capturePipeline.videoDimensions.width, _capturePipeline.videoDimensions.height];
    self.dimensionsLabel.text = dimensionsString;
}

#pragma mark - DKCapturePipelineDelegate

- (void)capturePipeline:(DKCapturePipeline *)capturePipeline didStopRunningWithError:(NSError *)error
{
    [self showError:error];
}

// Preview
- (void)capturePipeline:(DKCapturePipeline *)capturePipeline previewPixelBufferReadyForDisplay:(CVPixelBufferRef)previewPixelBuffer
{
    if ( ! _allowedToUseGPU ) {
        return;
    }
    
    [self.previewView displayPixelBuffer:previewPixelBuffer];
}

- (void)capturePipelineDidRunOutOfPreviewBuffers:(DKCapturePipeline *)capturePipeline
{
    if ( _allowedToUseGPU ) {
        [self.previewView flushPixelBufferCache];
    }
}

// Recording
- (void)capturePipelineRecordingDidStart:(DKCapturePipeline *)capturePipeline
{
    
}

- (void)capturePipelineRecordingWillStop:(DKCapturePipeline *)capturePipeline
{

}

- (void)capturePipelineRecordingDidStop:(DKCapturePipeline *)capturePipeline
{
    [self recordingStopped];
    if (self.recordStopedBlock) {
        self.recordStopedBlock([DKCapturePipeline thumbnailImageForVideo:[_capturePipeline getLastedTempVideoUrl] atTime:[NSDate date].timeIntervalSinceNow], [_capturePipeline getLastedTempVideoUrl]);
    }
}

- (void)capturePipeline:(DKCapturePipeline *)capturePipeline recordingDidFailWithError:(NSError *)error
{
    [self recordingStopped];
    [self showError:error];
}


#pragma mark showError

- (void)showError:(NSError *)error
{
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:error.localizedDescription
                                                        message:error.localizedFailureReason
                                                       delegate:nil
                                              cancelButtonTitle:@"OK"
                                              otherButtonTitles:nil];
    [alertView show];
}

#pragma mark get set

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

- (BOOL)prefersStatusBarHidden
{
    return YES;
}

#pragma mark hit touch
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    
    return self;
}

#pragma mark lazy
- (DKCapturePipeline *)capturePipeline
{
    if (!_capturePipeline) {
        _capturePipeline = [[DKCapturePipeline alloc] initWithDelegate:self callbackQueue:dispatch_get_main_queue()];
    }
    return _capturePipeline;
}

- (OpenGLPixelBufferView *)previewView
{
    if (!_previewView) {
        // Set up GL view
        _previewView = [[OpenGLPixelBufferView alloc] initWithFrame:CGRectZero];
        _previewView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
        
        UIInterfaceOrientation currentInterfaceOrientation = [UIApplication sharedApplication].statusBarOrientation;
        _previewView.transform = [self.capturePipeline transformFromVideoBufferOrientationToOrientation:(AVCaptureVideoOrientation)currentInterfaceOrientation withAutoMirroring:YES]; // Front camera preview should be mirrored
        
        CGRect bounds = CGRectZero;
        bounds.size = [self convertRect:self.bounds toView:_previewView].size;
        _previewView.bounds = bounds;
        _previewView.center = CGPointMake( self.bounds.size.width/2.0, self.bounds.size.height/2.0 );
        
    }
    return _previewView;
}

- (UILabel *)framerateLabel
{
    if (!_framerateLabel) {
        _framerateLabel = [[UILabel alloc] initWithFrame:CGRectMake(self.frame.size.width - 100, 100, 100, 21)];
        _framerateLabel.textColor = [UIColor redColor];
    }
    return _framerateLabel;
}

- (UILabel *)dimensionsLabel
{
    if (!_dimensionsLabel) {
        _dimensionsLabel = [[UILabel alloc] initWithFrame:CGRectMake(self.frame.size.width - 100, 125, 100, 21)];
        _dimensionsLabel.textColor = [UIColor redColor];
    }
    return _dimensionsLabel;
}

@end
